package com.asen.libcommon.base.viewbind

import android.app.Activity
import android.app.Dialog
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.viewbinding.ViewBinding
import com.lxj.xpopup.core.BasePopupView
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * @date   : 2021/2/7
 * @author : asenLiang
 * @e-mail : liangAisiSen@163.com
 * @desc   : viewBinding 绑定 xml 布局扩展函数
 */

// TODO: activity viewBinding 绑定 (延时委托)，因为是懒加载，所以只有使用到它的时候才触发
inline fun <reified T : ViewBinding> Activity.viewBind() = lazy {
    (T::class.java.inflateMethod().invoke(null, layoutInflater) as T).apply { setContentView(root) }
}

// TODO: dialog viewBinding 绑定 (延时委托)，因为是懒加载，所以只有使用到它的时候才触发
inline fun <reified T : ViewBinding> Dialog.viewBind() = lazy {
    (T::class.java.inflateMethod().invoke(null, layoutInflater) as T).apply { setContentView(root) }
}

// TODO: fragment viewBinding 绑定 (属性委托)
inline fun <reified T : ViewBinding> Fragment.viewBind() =
    FragmentViewBinding(T::class.java)

/**
 * fragment 属性委托封装
 */
class FragmentViewBinding<T : ViewBinding>(
    private val clazz: Class<T>,
    private var viewBinding: T? = null
) : ReadOnlyProperty<Fragment, T> {

    override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
        return viewBinding?.run {
            return this
        } ?: let {
            val bind: T = if (thisRef.view == null)
            // TODO: 这里为了兼容在 navigation 中使用 Fragment
                clazz.inflateMethod().invoke(null, thisRef.layoutInflater) as T
            else clazz.bindMethod().invoke(null, thisRef.view) as T

            return bind.apply {
                viewBinding = this
                thisRef.viewLifecycleOwner.lifecycle.addObserver(
                    ViewBindLifecycleObserver(
                        viewBinding
                    )
                )
            }
        }
    }

    internal class ViewBindLifecycleObserver<T : ViewBinding>(
        private var viewBinding: T?,
        private val mainHandler: Handler = Handler(Looper.getMainLooper())
    ) : LifecycleObserver {

        // TODO: activity/fragment 注意，因为 屏幕旋转 的时候会触发 onDestroy() 或则
        //       按Home键/按关机键 系统回收内存机制触发也会发生，这个样子就导致 viewBinding == null
        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        fun onDestroy() {
            mainHandler.post {
                viewBinding = null
            }
        }

    }
}

// TODO: inflate 方法反射调用
fun <T> Class<T>.inflateMethod() = getMethod("inflate", LayoutInflater::class.java)

// TODO: bind 方法反射调用
fun <T> Class<T>.bindMethod() = getMethod("bind", View::class.java)


/** BasePopupView */
inline fun <reified VB : ViewBinding> BasePopupView.bindView() = lazy {
    bindToImplView(VB::class.java, popupImplView).apply { }
}

fun <VB : ViewBinding> bindToImplView(clazz: Class<VB>, view: View) =
    clazz.getMethod("bind", View::class.java).invoke(null, view) as VB

